package com.scs.application.core.utils;

import com.scs.application.modules.dept.entity.DeptReturnItem;
import com.scs.application.modules.dept.entity.OprtUseItem;
import com.scs.application.modules.dept.entity.UseDtl;
import com.scs.application.modules.wm.entity.PickItem;
import com.scs.application.modules.wm.entity.Stock;
import com.scs.application.modules.wm.entity.TransferItem;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @ Description：jdk8的一些工具类
 */
public class UtilJava8 {
    /**
     * @Description：字段去重
     */
    public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object,Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    /**
     * <pre>
     *     将库存列表分组去重，按照 供应商id，耗材id【不要了】，寄售类型，一物一码类型
     *     一般用于生成出库单前进行分组
     * </pre>
     * @param stockList 需要分组的库存列表
     * @return  分组后的库存数组, stockList == null || stockList.size() <1 返回 null
     */
    synchronized  public static List<Stock> stockGroup(List<Stock> stockList) {
        if (stockList == null || stockList.size() <1) return null;
        return stockList.stream().filter(
                distinctByKey(stock -> stock.getSupplierId()+stock.getFlagConsignment()+stock.getFlagOmoc())
        ).collect(Collectors.toList());
    }

    /**
     * <pre>
     *     筛选库存列表，供应商id，耗材id【不要了】，寄售类型，一物一码类型 与stockGroup 匹配的
     * </pre>
     * @param stockList    未分组的库存列表
     * @param stockGroup    库存分组条件
     * @return  分组后的库存数组, stockList == null || stockList.size() <1 返回 null
     */
    synchronized  public static List<Stock> stockFilter(List<Stock> stockList,Stock stockGroup) {
        if (stockList == null || stockList.size() <1) return null;
       return stockList.stream().filter(stockTmp ->
                       stockTmp.getSupplierId().equals(stockGroup.getSupplierId())
                       &&  stockTmp.getFlagConsignment() == stockGroup.getFlagConsignment()
                       &&  stockTmp.getFlagOmoc() == stockGroup.getFlagOmoc()
       ).collect(Collectors.toList());
    }

    /**
     * <pre>病人消耗单
     *     转出入库时，过滤消耗明细
     *     筛选busObjs里面，使用stockList的数据
     * </pre>
     * @param stockList    经过分组筛选的库存列表
     * @param busDtlsAll       明细列表
     * @return  库存里面出现过的明细列表, stockList == null || stockList.size() <1 返回 null
     */
    synchronized  public static List<OprtUseItem> getWODeptOprtUseItems(List<Stock> stockList,List<OprtUseItem> busDtlsAll) {
        if (stockList == null || stockList.size() <1) return null;
       return busDtlsAll.stream().filter(busObj -> stockList.stream().anyMatch(stockAdd->stockAdd.getId().equals(busObj.getStockId()))).collect(Collectors.toList());
    }


    /**
     * <pre>配送单
     *     转出入库时，过滤消耗明细
     *     筛选busObjs里面，使用stockList的数据
     * </pre>
     * @param stockList    经过分组筛选的库存列表
     * @param busDtlsAll       明细列表
     * @return  库存里面出现过的明细列表, stockList == null || stockList.size() <1 返回 null
     */
    synchronized  public static List<PickItem> getWODistPickItems(List<Stock> stockList,List<PickItem> busDtlsAll) {
        if (stockList == null || stockList.size() <1) return null;
        return busDtlsAll.stream().filter(busObj -> stockList.stream().anyMatch(stockAdd->stockAdd.getId().equals(busObj.getStockId()))).collect(Collectors.toList());
    }

    /**
     * <pre>调拨单,生成出库单，入库单是由出库单复制过去的，不存在问题
     *     转出入库时，过滤消耗明细
     *     筛选busObjs里面，使用stockList的数据
     * </pre>
     * @param stockList    经过分组筛选的库存列表
     * @param busDtlsAll       明细列表
     * @return  库存里面出现过的明细列表, stockList == null || stockList.size() <1 返回 null
     */
    synchronized  public static List<TransferItem> getWOTransferItems(List<Stock> stockList,List<TransferItem> busDtlsAll) {
        if (stockList == null || stockList.size() <1) return null;
        return busDtlsAll.stream().filter(busObj -> stockList.stream().anyMatch(stockAdd->stockAdd.getId().equals(busObj.getStockId()))).collect(Collectors.toList());
    }

    /**
     * <pre>科室退库单
     *     转出入库时，过滤消耗明细
     *     筛选busObjs里面，使用stockList的数据
     * </pre>
     * @param stockList    经过分组筛选的库存列表
     * @param busDtlsAll       明细列表
     * @return  库存里面出现过的明细列表, stockList == null || stockList.size() <1 返回 null
     */
    synchronized  public static List<DeptReturnItem> getWODeptReturnItems(List<Stock> stockList,List<DeptReturnItem> busDtlsAll) {
        if (stockList == null || stockList.size() <1) return null;
        return busDtlsAll.stream().filter(busObj -> stockList.stream().anyMatch(stockAdd->stockAdd.getId().equals(busObj.getStockId()))).collect(Collectors.toList());
    }

    /**
     * <pre>科室消耗单
     *     转出入库时，过滤消耗明细
     *     筛选busObjs里面，使用stockList的数据
     * </pre>
     * @param stockList    经过分组筛选的库存列表
     * @param busDtlsAll       明细列表
     * @return  库存里面出现过的明细列表, stockList == null || stockList.size() <1 返回 null
     */
    synchronized  public static List<UseDtl> getWODeptUseItems(List<Stock> stockList, List<UseDtl> busDtlsAll) {
        if (stockList == null || stockList.size() <1) return null;
        return busDtlsAll.stream().filter(busObj -> stockList.stream().anyMatch(stockAdd->stockAdd.getId().equals(busObj.getStockId()))).collect(Collectors.toList());
    }


    /**
     * <pre>
     *     批量上架分组去重，按照  耗材id，包装单位
     *     一般用于生成出库单前进行分组
     * </pre>
     * @param stockList 需要分组的库存列表
     * @return  分组后的库存数组, stockList == null || stockList.size() <1 返回 null
     */
    synchronized  public static List<Stock> stockGroupForUpShelvesBatch(List<Stock> stockList) {
        if (stockList == null || stockList.size() <1) return null;
        return stockList.stream().filter(
                distinctByKey(stock ->  stock.getMatrId()+stock.getPackageUnit() )
        ).collect(Collectors.toList());
    }

    /**
     * <pre>
     *     筛选库存列表， 耗材id，包装单位
     * </pre>
     * @param stockList    未分组的库存列表
     * @param stockGroup    库存分组条件
     * @return  分组后的库存数组, stockList == null || stockList.size() <1 返回 null
     */
    synchronized  public static List<Stock> stockFilterForUpShelvesBatch(List<Stock> stockList,Stock stockGroup) {
        if (stockList == null || stockList.size() <1) return null;
        return stockList.stream().filter(stockTmp ->
                stockTmp.getMatrId().equals(stockGroup.getMatrId())
                        &&  stockTmp.getPackageUnit().equals(stockGroup.getPackageUnit())
        ).collect(Collectors.toList());
    }

    /**
     * <pre>
     *     智能柜入库通知分组去重，按照  物理仓库id
     *     一般用于生成出库单前进行分组
     * </pre>
     * @param stockList 需要分组的库存列表
     * @return  分组后的库存数组, stockList == null || stockList.size() <1 返回 null
     */
    synchronized  public static List<Stock> stockGroupForWiNotify(List<Stock> stockList) {
        if (stockList == null || stockList.size() <1) return null;
        return stockList.stream().filter(
                distinctByKey(stock ->  stock.getWarehouseId())
        ).collect(Collectors.toList());
    }


    /**
     * <pre>
     *     筛选库存列表， 仓库Id，库位id
     * </pre>
     * @param stockList    未分组的库存列表
     * @param stockGroup    库存分组条件
     * @return  分组后的库存数组, stockList == null || stockList.size() <1 返回 null
     */
    synchronized  public static List<Stock> stockFilterForWiNotify(List<Stock> stockList,Stock stockGroup) {
        if (stockList == null || stockList.size() <1) return null;
        return stockList.stream().filter(stockTmp ->
                stockTmp.getWarehouseId().equals(stockGroup.getWarehouseId())
        ).collect(Collectors.toList());
    }

    /**
     * <pre>
     *     批量解锁使用，按照  耗材id
     * </pre>
     * @param stockList 需要分组的库存列表
     * @return  分组后的库存数组, stockList == null || stockList.size() <1 返回 null
     */
    public static List<Stock> stockGroupForUnlockBatch(List<Stock> stockList) {
        if (stockList == null || stockList.size() <1) return null;
        return stockList.stream().filter(
                distinctByKey(stock ->stock.getMatrId())
        ).collect(Collectors.toList());
    }
}
